package org.ims.inv.service.flow.impl;

import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.ims.inv.model.flow.ModelFlowBase;
import org.ims.inv.model.flow.ModelFlowDef;
import org.ims.inv.model.flow.ModelFlowTemplate;
import org.ims.inv.model.flow.material.ModelFlowMaterial;
import org.ims.inv.service.flow.ServiceFlowConfer;
import org.ims.inv.service.flow.ServiceFlowDefinition;
import org.ims.inv.service.flow.ServiceFlowMaterial;
import org.ims.inv.service.flow.ServiceFlowTemplate;
import org.ims.inv.service.flow.ServiceWorkFlow;

import cn.trymore.core.exception.ServiceException;
import cn.trymore.core.util.UtilCollection;

/**
 * Service: 工作流
 * 
 * @author Jeccy.Zhao
 *
 */
public class ServiceWorkFlowImpl
implements ServiceWorkFlow
{
	/**
	 * Service of flow definition
	 */
	private ServiceFlowDefinition serviceFlowDefinition;
	
	/**
	 * Service of flow template
	 */
	private ServiceFlowTemplate serviceFlowTemplate;
	
	/**
	 * Service of flow material
	 */
	private ServiceFlowMaterial serviceFlowMaterial;
	
	/**
	 * Service of flow conference
	 */
	private ServiceFlowConfer serviceFlowConfer;
	
	/*
	 * (non-Javadoc)
	 * @see org.ims.inv.service.flow.ServiceFlowDefinition#dropFlowDefinition(java.lang.String)
	 */
	public void activateFlowDefinition (String defId) throws ServiceException
	{
		configureFlowDefinitionStatus(defId, ModelFlowDef.DEF_APPLIED);
	}
	
	/*
	 * (non-Javadoc)
	 * @see org.ims.inv.service.flow.ServiceFlowDefinition#dropFlowDefinition(java.lang.String)
	 */
	public void dropFlowDefinition (String defId) throws ServiceException
	{
		configureFlowDefinitionStatus(defId, ModelFlowDef.DEF_DROPPED);
	}
	
	/*
	 * (non-Javadoc)
	 * @see org.ims.inv.service.flow.ServiceWorkFlow#getAvailableSeqs(java.lang.String, java.lang.String)
	 */
	public int getAvailableSeqs (String entityId, String source) throws ServiceException
	{
		if (ModelFlowBase.SRC_PROCESS_TEMPLATE.equalsIgnoreCase(source))
		{
			ModelFlowTemplate entity = this.serviceFlowTemplate.get(entityId);
			if (entity != null && entity.getFlowDef() != null)
			{
				return UtilCollection.isNotEmpty(entity.getFlowDef().getTemplates()) ? entity.getFlowDef().getTemplates().size() : 0;
			}
		}
		else if (ModelFlowBase.SRC_PROCESS_MATERIAL.equalsIgnoreCase(source))
		{
			ModelFlowMaterial entity = this.serviceFlowMaterial.get(entityId);
			if (entity == null || entity.getMaterialParent() == null)
			{
				List<ModelFlowMaterial> rootMaterials = this.serviceFlowMaterial.getAllRootMaterials();
				return UtilCollection.isNotEmpty(rootMaterials) ? rootMaterials.size() : 0;
			}
			else
			{
				List<ModelFlowMaterial> subMaterials = this.serviceFlowMaterial.getByRootMaterial(entity.getMaterialParent());
				return UtilCollection.isNotEmpty(subMaterials) ? subMaterials.size() : 0;
			}
		}
		else if (ModelFlowBase.SRC_PROCESS_DEF.equalsIgnoreCase(source))
		{
			ModelFlowDef entity = this.serviceFlowDefinition.get(entityId);
			if (entity != null)
			{
				return UtilCollection.isNotEmpty(entity.getTemplates()) ? entity.getTemplates().size() : 0;
			}
		}
		else
		{
			throw new ServiceException("Unsupported process source detected:" + source);
		}
		
		return 0;
	}
	
	/*
	 * (non-Javadoc)
	 * @see org.ims.inv.service.flow.ServiceWorkFlow#getBySequence(java.lang.Integer, java.lang.String, org.ims.inv.model.flow.ModelFlowBase)
	 */
	public ModelFlowBase getBySequence (Integer sequence, String source, ModelFlowBase entity) throws ServiceException
	{
		if (ModelFlowBase.SRC_PROCESS_TEMPLATE.equalsIgnoreCase(source))
		{
			return this.serviceFlowTemplate.getBySequence(sequence, (ModelFlowTemplate)entity);
		}
		else if (ModelFlowBase.SRC_PROCESS_MATERIAL.equalsIgnoreCase(source))
		{
			return this.serviceFlowMaterial.getBySequence(sequence, (ModelFlowMaterial)entity);
		}
		else
		{
			throw new ServiceException("Unsupported process source detected:" + source);
		}
	}
	
	/*
	 * (non-Javadoc)
	 * @see org.ims.inv.service.flow.ServiceFlowTemplate#refreshFlowSequenceMap()
	 */
	@Override
	public void refreshFlowSequenceMap (String defId) throws ServiceException
	{
		ModelFlowDef entity = this.serviceFlowDefinition.get(defId);
		if (entity != null)
		{
			Integer startSeq = 1;
			Set<ModelFlowTemplate> templates = entity.getTemplates();
			if (UtilCollection.isNotEmpty(templates))
			{
				Iterator<ModelFlowTemplate> itor = templates.iterator();
				while (itor.hasNext())
				{
					ModelFlowTemplate template = itor.next();
					if (!template.getSequence().equals(startSeq))
					{
						template.setSequence(startSeq);
					}
					startSeq++;
				}
				
				this.serviceFlowDefinition.save(entity);
			}
		}
		else
		{
			throw new ServiceException("Entity does not exist with id:" + defId);
		}
		
	}
	
	/*
	 * (non-Javadoc)
	 * @see org.ims.inv.service.flow.ServiceWorkFlow#refreshMaterialSequenceMap(org.ims.inv.model.flow.material.ModelFlowMaterial)
	 */
	@Override
	public void refreshMaterialSequenceMap (ModelFlowMaterial parent) throws ServiceException
	{
		List<ModelFlowMaterial> materials = this.serviceFlowMaterial.getByRootMaterial(parent);
		if (UtilCollection.isNotEmpty(materials))
		{
			Integer startSeq = 1;
			Iterator<ModelFlowMaterial> itor = materials.iterator();
			while (itor.hasNext())
			{
				ModelFlowMaterial material = itor.next();
				if (!material.getSequence().equals(startSeq))
				{
					material.setSequence(startSeq);
					this.serviceFlowMaterial.save(material);
				}
				startSeq++;
			}
		}
	}
	/**
	 * Configures flow definition entity status
	 * 
	 * @param defId
	 * @param status
	 * @throws ServiceException
	 */
	private void configureFlowDefinitionStatus (String defId, Integer status) throws ServiceException
	{
		ModelFlowDef entity = this.serviceFlowDefinition.get(defId);
		if (entity != null)
		{
			ModelFlowDef currentAppliedEntity = this.serviceFlowDefinition.getCurrentAppliedDefinition();
			if (currentAppliedEntity != null)
			{
				if (!currentAppliedEntity.getId().equals(entity.getId()))
				{
					entity.setDefApplied(status);
					this.serviceFlowDefinition.save(entity);
					return;
				}
			}
		}
	}

	public void setServiceFlowDefinition(ServiceFlowDefinition serviceFlowDefinition)
	{
		this.serviceFlowDefinition = serviceFlowDefinition;
	}
	
	@Override
	public ServiceFlowDefinition getServiceFlowDefinition()
	{
		return serviceFlowDefinition;
	}

	public void setServiceFlowTemplate(ServiceFlowTemplate serviceFlowTemplate)
	{
		this.serviceFlowTemplate = serviceFlowTemplate;
	}
	
	@Override
	public ServiceFlowTemplate getServiceFlowTemplate()
	{
		return serviceFlowTemplate;
	}

	public void setServiceFlowMaterial(ServiceFlowMaterial serviceFlowMaterial)
	{
		this.serviceFlowMaterial = serviceFlowMaterial;
	}

	@Override
	public ServiceFlowMaterial getServiceFlowMaterial()
	{
		return serviceFlowMaterial;
	}

	public void setServiceFlowConfer(ServiceFlowConfer serviceFlowConfer)
	{
		this.serviceFlowConfer = serviceFlowConfer;
	}

	public ServiceFlowConfer getServiceFlowConfer()
	{
		return serviceFlowConfer;
	}
}
